/**
 *   Copyright 2023 Han-Kuiwei
 *
 *    Licensed under the Apache License, Version 2.0 (the "License");
 *    you may not use this file except in compliance with the License.
 *    You may obtain a copy of the License at
 *
 *        http://www.apache.org/licenses/LICENSE-2.0
 *
 *    Unless required by applicable law or agreed to in writing, software
 *    distributed under the License is distributed on an "AS IS" BASIS,
 *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *    See the License for the specific language governing permissions and
 *    limitations under the License.
 */
package com.hkw.daterangepicke;


import android.content.Context;
import android.util.AttributeSet;
import android.util.Log;
import android.view.View;
import androidx.annotation.NonNull;
import com.github.gzuliyujiang.wheelview.contract.WheelFormatter;
import com.github.gzuliyujiang.wheelview.widget.NumberWheelView;
import com.github.gzuliyujiang.wheelview.widget.WheelView;
import com.hkw.daterangepicke.contract.DateFormatter;
import com.hkw.daterangepicke.impl.SimpleDateFormatter;
import com.hkw.daterangepicke.widget.BaseWheelLayout;

import java.util.Arrays;
import java.util.List;

public class DateTimeWheelLayout extends BaseWheelLayout {
    private DateTimeEntity endValue;

    private OnDateTimeSelectedListener onDateTimeSelectedListener;

    private boolean resetWhenLinkage = true;

    private Integer selectedDay;

    private Integer selectedMonth;

    private Integer selectedYear;

    private DateTimeEntity startValue;

    private String tag = "DateTimeWheelLayout";

    private NumberWheelView wheelDay;

    private NumberWheelView wheelMonth;

    private NumberWheelView wheelYear;

    public DateTimeWheelLayout(Context paramContext) {
        super(paramContext);
    }

    public DateTimeWheelLayout(Context paramContext, AttributeSet paramAttributeSet) {
        super(paramContext, paramAttributeSet);
    }

    public DateTimeWheelLayout(Context paramContext, AttributeSet paramAttributeSet, int paramInt) {
        super(paramContext, paramAttributeSet, paramInt);
    }



    private void changeDay(int year, int month) {
        final int min, max;
        //开始年月及结束年月相同情况
        if (year == startValue.getYear() && month == startValue.getMonth()
                && year == endValue.getYear() && month == endValue.getMonth()) {
            min = startValue.getDay();
            max = endValue.getDay();
        }
        //开始年月相同情况
        else if (year == startValue.getYear() && month == startValue.getMonth()) {
            min = startValue.getDay();
            max = getTotalDaysInMonth(year, month);
        }
        //结束年月相同情况
        else if (year == endValue.getYear() && month == endValue.getMonth()) {
            min = 1;
            max = endValue.getDay();
        } else {
            min = 1;
            max = getTotalDaysInMonth(year, month);
        }
        if (selectedDay == null) {
            selectedDay = min;
        } else {
            selectedDay = Math.max(selectedDay, min);
            selectedDay = Math.min(selectedDay, max);
        }
        this.wheelDay.setRange(min, max, 1);
        this.wheelDay.setDefaultValue(selectedDay);
        dateSelectedCallback();
    }


    private void changeMonth(int year) {
        final int min, max;
        //开始年份和结束年份相同（即只有一个年份，这种情况建议使用月日模式）
        if (startValue.getYear() == endValue.getYear()) {
            min = Math.min(startValue.getMonth(), endValue.getMonth());
            max = Math.max(startValue.getMonth(), endValue.getMonth());
        }
        //当前所选年份和开始年份相同
        else if (year == startValue.getYear()) {
            min = startValue.getMonth();
            max = 12;
        }
        //当前所选年份和结束年份相同
        else if (year == endValue.getYear()) {
            min = 1;
            max = endValue.getMonth();
        }
        //当前所选年份在开始年份和结束年份之间
        else {
            min = 1;
            max = 12;
        }
        if (selectedMonth == null) {
            selectedMonth = min;
        } else {
            selectedMonth = Math.max(selectedMonth, min);
            selectedMonth = Math.min(selectedMonth, max);
        }

        this.wheelMonth.setRange(min, max, 1);
        this.wheelMonth.setDefaultValue(selectedMonth);
        changeDay(year, selectedMonth);
    }



    private void changeYear() {
        final int min = Math.min(startValue.getYear(), endValue.getYear());
        final int max = Math.max(startValue.getYear(), endValue.getYear());
        if (selectedYear == null) {
            selectedYear = min;
        } else {
            selectedYear = Math.max(selectedYear, min);
            selectedYear = Math.min(selectedYear, max);
        }
        this.wheelYear.setRange(min, max, 1);
        this.wheelYear.setDefaultValue(selectedYear);
        changeMonth(selectedYear);
    }

    private void dateSelectedCallback() {

        if (onDateTimeSelectedListener == null) {
            return;
        }
        this.wheelDay.post(new Runnable() {
            @Override
            public void run() {
                onDateTimeSelectedListener.onDateSelected(selectedYear, selectedMonth, selectedDay);
            }
        });
    }

    /**
     * 根据年份及月份获取每月的天数，类似于{@link java.util.Calendar#getActualMaximum(int)}
     */


private int getTotalDaysInMonth(int year, int month) {
        switch (month) {
            case 1:
            case 3:
            case 5:
            case 7:
            case 8:
            case 10:
            case 12:
                // 大月月份为31天
                return 31;
            case 4:
            case 6:
            case 9:
            case 11:
                // 小月月份为30天
                return 30;
            case 2:
                // 二月需要判断是否闰年
                if (year <= 0) {
                    return 29;
                }
                // 是否闰年：能被4整除但不能被100整除；能被400整除；
                boolean isLeap = (year % 4 == 0 && year % 100 != 0) || year % 400 == 0;
                if (isLeap) {
                    return 29;
                } else {
                    return 28;
                }
            default:
                return 30;
        }
    }

    public Integer getSelectedDay() {
        return this.selectedDay;
    }

    public Integer getSelectedMonth() {
        return this.selectedMonth;
    }

    public Integer getSelectedYear() {
        return this.selectedYear;
    }

    protected void onAttributeSet(Context paramContext, AttributeSet paramAttributeSet) {
        setDateFormatter(new SimpleDateFormatter());
    }

    protected void onInit(Context paramContext) {
        this.wheelYear = (NumberWheelView) findViewById(R.id.wheelYear);
        this.wheelMonth = (NumberWheelView) findViewById(R.id.wheelMonth);
        this.wheelDay = (NumberWheelView) findViewById(R.id.wheelDay);
    }

    protected void onVisibilityChanged(View paramView, int paramInt) {
        super.onVisibilityChanged(paramView, paramInt);
    }

    public void onWheelScrollStateChanged(WheelView paramWheelView, int paramInt) {
        int i = paramWheelView.getId();
        boolean bool1 = true;
        boolean bool2 = true;
        boolean bool3 = true;
        if (i == R.id.wheelYear) {
            boolean bool;
            NumberWheelView numberWheelView = this.wheelMonth;
            if (paramInt == 0) {
                bool = true;
            } else {
                bool = false;
            }
            numberWheelView.setEnabled(bool);
            numberWheelView = this.wheelDay;
            if (paramInt == 0) {
                bool = bool3;
            } else {
                bool = false;
            }
            numberWheelView.setEnabled(bool);
            return;
        }
        if (i == R.id.wheelMonth) {
            boolean bool;
            NumberWheelView numberWheelView = this.wheelYear;
            if (paramInt == 0) {
                bool = true;
            } else {
                bool = false;
            }
            numberWheelView.setEnabled(bool);
            numberWheelView = this.wheelDay;
            if (paramInt == 0) {
                bool = bool1;
            } else {
                bool = false;
            }
            numberWheelView.setEnabled(bool);
            return;
        }
        if (i == R.id.wheelDay) {
            boolean bool;
            NumberWheelView numberWheelView = this.wheelMonth;
            if (paramInt == 0) {
                bool = true;
            } else {
                bool = false;
            }
            numberWheelView.setEnabled(bool);
            numberWheelView = this.wheelYear;
            if (paramInt == 0) {
                bool = bool2;
            } else {
                bool = false;
            }
            numberWheelView.setEnabled(bool);
        }
    }



    @Override
    public void onWheelSelected(WheelView view, int position) {
        int id = view.getId();
        if (id == R.id.wheelYear) {
            selectedYear = this.wheelYear.getItem(position);
            if (resetWhenLinkage) {
                selectedMonth = null;
                selectedDay = null;
            }
            changeMonth(selectedYear);
            dateSelectedCallback();
            return;
        }
        if (id == R.id.wheelMonth) {
            selectedMonth = this.wheelMonth.getItem(position);
            if (resetWhenLinkage) {
                selectedDay = null;
            }
            changeDay(selectedYear, selectedMonth);
            dateSelectedCallback();
            return;
        }
        if (id == R.id.wheelDay) {
            selectedDay = this.wheelDay.getItem(position);
            dateSelectedCallback();
        }
    }

    protected int provideLayoutRes() {

        return R.layout.wheel_date_time;
    }

    protected List<WheelView> provideWheelViews() {
        return Arrays.asList(new WheelView[]{(WheelView) this.wheelYear, (WheelView) this.wheelMonth, (WheelView) this.wheelDay});
    }



    public void setDateFormatter(final DateFormatter dateFormatter) {
        if (dateFormatter == null) {
            return;
        }
        this.wheelYear.setFormatter(new WheelFormatter() {
            @Override
            public String formatItem(@NonNull Object value) {
                return dateFormatter.formatYear((Integer) value);
            }
        });
        this.wheelMonth.setFormatter(new WheelFormatter() {
            @Override
            public String formatItem(@NonNull Object value) {
                return dateFormatter.formatMonth((Integer) value);
            }
        });
        this.wheelDay.setFormatter(new WheelFormatter() {
            @Override
            public String formatItem(@NonNull Object value) {
                return dateFormatter.formatDay((Integer) value);
            }
        });
    }

    public void setDefaultValue(DateTimeEntity paramDateTimeEntity) {
        setRange(this.startValue, this.endValue, paramDateTimeEntity);
    }

    public void setOnDateTimeSelectedListener(OnDateTimeSelectedListener paramOnDateTimeSelectedListener) {
        this.onDateTimeSelectedListener = paramOnDateTimeSelectedListener;
    }

    public void setRange(DateTimeEntity paramDateTimeEntity1, DateTimeEntity paramDateTimeEntity2) {
        setRange(paramDateTimeEntity1, paramDateTimeEntity2, (DateTimeEntity) null);
    }

    public void setRange(DateTimeEntity paramDateTimeEntity1, DateTimeEntity paramDateTimeEntity2, DateTimeEntity paramDateTimeEntity3) {
        if (paramDateTimeEntity1 == null)
            return;
        if (paramDateTimeEntity2 == null)
            return;
        String str = this.tag;
        StringBuilder stringBuilder = new StringBuilder();
        stringBuilder.append("start = ");
        stringBuilder.append(paramDateTimeEntity1.getYear());
        stringBuilder.append(" end = ");
        stringBuilder.append(paramDateTimeEntity2.getYear());
        Log.e(str, stringBuilder.toString());
        this.startValue = paramDateTimeEntity1;
        this.endValue = paramDateTimeEntity2;
        if (paramDateTimeEntity3 != null) {
            this.selectedYear = Integer.valueOf(paramDateTimeEntity3.getYear());
            this.selectedMonth = Integer.valueOf(paramDateTimeEntity3.getMonth());
            this.selectedDay = Integer.valueOf(paramDateTimeEntity3.getDay());
        } else {
            this.selectedYear = null;
            this.selectedMonth = null;
            this.selectedDay = null;
        }
        changeYear();
    }




    public void setResetWhenLinkage(boolean paramBoolean) {
        this.resetWhenLinkage = paramBoolean;
    }
}
